home *** CD-ROM | disk | FTP | other *** search
/ PC World 2006 February / PCWorld_2006-02_cd.bin / software / vyzkuste / triky / triky.exe / httrack-3.33.exe / {app} / src / htsftp.c < prev    next >
C/C++ Source or Header  |  2005-02-05  |  34KB  |  1,152 lines

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20.  
  21. Important notes:
  22.  
  23. - We hereby ask people using this source NOT to use it in purpose of grabbing
  24. emails addresses, or collecting any other private information on persons.
  25. This would disgrace our work, and spoil the many hours we spent on it.
  26.  
  27.  
  28. Please visit our Website: http://www.httrack.com
  29. */
  30.  
  31.  
  32. /* ------------------------------------------------------------ */
  33. /* File: basic FTP protocol manager                             */
  34. /* Author: Xavier Roche                                         */
  35. /* ------------------------------------------------------------ */
  36.  
  37. /* Internal engine bytecode */
  38. #define HTS_INTERNAL_BYTECODE
  39.  
  40. // Gestion protocole ftp
  41. // Version .05 (01/2000)
  42.  
  43. #include "htsftp.h"
  44.  
  45. #include "htsglobal.h"
  46. #include "htsbase.h"
  47. #include "htsnet.h"
  48. #include "htsthread.h"
  49. #if HTS_WIN
  50. #else
  51. //inet_ntoa
  52. #include <arpa/inet.h>
  53. #endif
  54.  
  55. #if HTS_WIN
  56. #ifndef __cplusplus
  57. // DOS
  58. #ifndef  _WIN32_WCE
  59. #include <process.h>    /* _beginthread, _endthread */
  60. #endif
  61. #endif
  62. #endif
  63.  
  64. // ftp mode passif
  65. // #if HTS_INET6==0
  66. #define FTP_PASV 1
  67. // #else
  68. // no passive mode for v6
  69. // #define FTP_PASV 0
  70. // #endif
  71.  
  72. #define FTP_DEBUG 0
  73. //#define FORK_DEBUG 0
  74.  
  75. #define FTP_STATUS_READY 1001
  76.  
  77. #if USE_BEGINTHREAD
  78.  
  79. PTHREAD_TYPE PTHREAD_TYPE_FNC back_launch_ftp( void* pP ) {
  80.   lien_back* back=(lien_back*) pP;
  81.   if (back == NULL) {
  82. #if FTP_DEBUG
  83.     printf("[ftp error: no args]\n");
  84. #endif
  85.     return PTHREAD_RETURN;
  86.   }
  87.  
  88.   /* Initialize */ 
  89.   hts_init();
  90.  
  91.   // lancer ftp
  92. #if FTP_DEBUG
  93.   printf("[Launching main ftp routine]\n");
  94. #endif
  95.   run_launch_ftp(back);
  96.   // prΩt
  97.   back->status=FTP_STATUS_READY;
  98.   
  99.   /* Uninitialize */
  100.   hts_uninit();
  101.   return PTHREAD_RETURN;
  102. }
  103. // lancer en back
  104. void launch_ftp(lien_back* back) {
  105.   // DOS
  106. #if FTP_DEBUG
  107.   printf("[Launching main ftp thread]\n");
  108. #endif
  109.   (void)hts_newthread(back_launch_ftp, 0, (void*) back);
  110. }
  111.  
  112. #else
  113. // Unix sans pthread
  114. int back_launch_ftp(lien_back* back) {
  115.   // lancer ftp
  116.   run_launch_ftp(back);
  117.   // prΩt
  118.   back->status=FTP_STATUS_READY;
  119.   return 0;
  120. }
  121. void launch_ftp(lien_back* back,char* path,char* exec) {
  122.   FILE* fp = fopen(fconv(path),"wb");
  123.   if (fp) {
  124.     char _args[8][256];
  125.     char *args[8];
  126.     fclose(fp); fp=NULL;
  127.     
  128.     strcpybuff(_args[0],exec);
  129.     strcpybuff(_args[1],"-#R");
  130.     strcpybuff(_args[2],back->url_adr);
  131.     strcpybuff(_args[3],back->url_fil);
  132.     strcpybuff(_args[4],back->url_sav);
  133.     strcpybuff(_args[5],path);
  134.     //strcpybuff(_args[6],"");
  135.     args[0]=_args[0];
  136.     args[1]=_args[1];
  137.     args[2]=_args[2];
  138.     args[3]=_args[3];
  139.     args[4]=_args[4];
  140.     args[5]=_args[5];
  141.     args[6]=NULL;
  142.     switch (fork()) {    // note: vfork dΘconne un max'
  143.     case -1: printf("Can not vfork() process\n"); break;
  144.     case 0: 
  145.       if (execvp(args[0],args)==-1) {
  146.         fp=fopen(fconv(path),"wb");
  147.         if (fp) {
  148.           fprintf(fp,"-1 unable to launch %s",args[0]);
  149.           fclose(fp); fp=NULL;
  150.           rename(path,concat(path,".ok"));
  151.         } else remove(path);
  152.       }
  153.       _exit(0);    // exit 'propre'
  154.       break;
  155.     default:  // parent
  156.       // bah on fait rien..
  157.       break;         
  158.     }
  159.   }
  160. }
  161. #endif
  162.  
  163. // pour l'arrΩt du ftp
  164. #ifdef _WIN32
  165. #define _T_SOC_close(soc)  closesocket(soc); soc=INVALID_SOCKET;
  166. #else
  167. #define _T_SOC_close(soc)  close(soc); soc=INVALID_SOCKET;
  168. #endif
  169. #define _HALT_FTP { \
  170.   if ( soc_ctl     != INVALID_SOCKET ) _T_SOC_close(soc_ctl); \
  171.   if ( soc_servdat != INVALID_SOCKET ) _T_SOC_close(soc_servdat); \
  172.   if ( soc_dat     != INVALID_SOCKET ) _T_SOC_close(soc_dat); \
  173. }
  174. #define _CHECK_HALT_FTP \
  175.   if (stop_ftp(back)) { \
  176.   _HALT_FTP \
  177.   return 0; \
  178.   }
  179.  
  180. // la vΘritable fonction une fois lancΘes les routines thread/fork
  181. int run_launch_ftp(lien_back* back) {
  182.   char user[256]="anonymous";
  183.   char pass[256]="user@";
  184.   char line_retr[2048];
  185.   int port=21;
  186. #if FTP_PASV
  187.   int port_pasv=0;
  188. #endif
  189.   char BIGSTK adr_ip[1024];
  190.   char *adr,*real_adr;
  191.   char* ftp_filename="";
  192.   int timeout = 300;    // timeout
  193.   int timeout_onfly=8;  // attente rΘponse supplΘmentaire
  194.   int transfer_list=0;  // directory
  195.   int rest_understood=0;  // rest command understood
  196.   t_fullhostent fullhostent_buffer;   // buffer pour resolver
  197.   //
  198.   T_SOC soc_ctl=INVALID_SOCKET;
  199.   T_SOC soc_servdat=INVALID_SOCKET;
  200.   T_SOC soc_dat=INVALID_SOCKET;
  201.   //
  202.   SOCaddr server_data;
  203.   int server_data_size=sizeof(server_data);
  204.   //
  205.   line_retr[0]=adr_ip[0]='\0';
  206.   
  207.   timeout=300;
  208.   
  209.   // effacer
  210.   strcpybuff(back->r.msg,"");
  211.   back->r.statuscode=0;
  212.   back->r.size=0;
  213.   
  214.   // rΘcupΘrer user et pass si prΘsents, et sauter user:id@ dans adr
  215.   real_adr = strchr(back->url_adr,':');
  216.   if (real_adr) real_adr++;
  217.   else real_adr=back->url_adr;
  218.   while(*real_adr=='/') real_adr++;    // sauter /
  219.   if ( (adr = jump_identification(real_adr)) != real_adr) {  // user
  220.     int i=-1;
  221.     pass[0]='\0';
  222.     do {
  223.       i++;
  224.       user[i]=real_adr[i];
  225.     } while( (real_adr[i]!=':') && (real_adr[i]) );
  226.     user[i]='\0';
  227.     if (real_adr[i]==':') {    // pass
  228.       int j=-1;
  229.       i++;  // oui on saute aussi le :
  230.       do {
  231.         j++;
  232.         pass[j]=real_adr[i+j];
  233.       } while( ((&real_adr[i+j+1]) < adr) && (real_adr[i+j]) );
  234.       pass[j]='\0';
  235.     }
  236.   }
  237.   
  238.   // Calculer RETR <nom>
  239.   {
  240.     char* a;
  241. #if 0
  242.     a=back->url_fil + strlen(back->url_fil)-1;
  243.     while( (a > back->url_fil) && (*a!='/')) a--;
  244.     if (*a != '/') {
  245.       a = NULL;
  246.     }
  247. #else
  248.     a = back->url_fil;
  249. #endif
  250.     if (a != NULL && *a != '\0') {
  251. #if 0
  252.       a++;    // sauter /
  253. #endif
  254.       ftp_filename=a;
  255.       if (strnotempty(a)) {
  256.         char* ua=unescape_http(a);
  257.         int len_a = (int) strlen(ua);
  258.         if (len_a > 0 && ua[len_a -1] == '/') {     /* obviously a directory listing */
  259.           transfer_list=1;
  260.           sprintf(line_retr,"LIST -A %s",ua);
  261.         } else if (
  262.           (strchr(ua, ' '))
  263.           ||
  264.           (strchr(ua, '\"'))
  265.           ||
  266.           (strchr(ua, '\''))
  267.           ) {
  268.           sprintf(line_retr,"RETR \"%s\"",ua);
  269.         } else {      /* Regular one */
  270.           sprintf(line_retr,"RETR %s",ua);
  271.         }
  272.       } else {
  273.         transfer_list=1;
  274.         sprintf(line_retr,"LIST -A");
  275.       }
  276.     } else {
  277.       strcpybuff(back->r.msg,"Unexpected PORT error");
  278.       // back->status=FTP_STATUS_READY;    // fini
  279.       back->r.statuscode=-1;
  280.     }
  281.   }
  282.   
  283. #if FTP_DEBUG
  284.   printf("Connecting to %s...\n",adr);
  285. #endif
  286.   
  287.   // connexion
  288.   {
  289.     SOCaddr server;
  290.     int server_size=sizeof(server);
  291.     t_hostent* hp;    
  292.     char * a;
  293.     char _adr[256];
  294.     _adr[0]='\0';
  295.     //T_SOC soc_ctl;
  296.     // effacer structure
  297.     memset(&server, 0, sizeof(server));
  298.     
  299.     // port
  300.     a=strchr(adr,':');    // port
  301.     if (a) {
  302.       sscanf(a+1,"%d",&port);
  303.       strncatbuff(_adr,adr,(int) (a - adr));
  304.     } else
  305.       strcpybuff(_adr,adr);
  306.     
  307.     // rΘcupΘrer adresse rΘsolue
  308.     strcpybuff(back->info,"host name");
  309.     hp = hts_gethostbyname(_adr, &fullhostent_buffer);
  310.     if (hp == NULL) {
  311.       strcpybuff(back->r.msg,"Unable to get server's address");
  312.       // back->status=FTP_STATUS_READY;    // fini
  313.       back->r.statuscode=-5;
  314.       _HALT_FTP
  315.         return 0;
  316.     }
  317.     _CHECK_HALT_FTP;
  318.     
  319.     // copie adresse
  320.     SOCaddr_copyaddr(server, server_size, hp->h_addr_list[0], hp->h_length);
  321.     // copie adresse pour cnx data
  322.     SOCaddr_copyaddr(server_data, server_data_size, hp->h_addr_list[0], hp->h_length);
  323.     // memcpy(&server.sin_addr, hp->h_addr, hp->h_length);
  324.     
  325.     // crΘer ("attachement") une socket (point d'accΦs) internet,en flot
  326.     soc_ctl=socket(SOCaddr_sinfamily(server), SOCK_STREAM, 0);
  327.     if (soc_ctl==INVALID_SOCKET) {
  328.       strcpybuff(back->r.msg,"Unable to create a socket");
  329.       // back->status=FTP_STATUS_READY;    // fini
  330.       back->r.statuscode=-1;
  331.       _HALT_FTP
  332.         return 0;
  333.     }
  334.  
  335.     SOCaddr_initport(server, port);
  336.     // server.sin_port = htons((unsigned short int) port);
  337.     
  338.     // connexion (bloquante, on est en thread)
  339.     strcpybuff(back->info,"connect");
  340.  
  341. #if HTS_WIN
  342.     if (connect(soc_ctl, (const struct sockaddr FAR *)&server, server_size) != 0) {
  343. #else
  344.       if (connect(soc_ctl, (struct sockaddr *)&server, server_size) == -1) {
  345. #endif
  346.         strcpybuff(back->r.msg,"Unable to connect to the server");
  347.         // back->status=FTP_STATUS_READY;    // fini
  348.         back->r.statuscode=-1;
  349.         _HALT_FTP
  350.           return 0;
  351. #if HTS_WIN
  352.       }
  353. #else
  354.     }
  355. #endif
  356.     _CHECK_HALT_FTP;
  357.     
  358.     {
  359.       char BIGSTK line[1024];
  360.       // envoi du login
  361.       
  362.       // --USER--
  363.       get_ftp_line(soc_ctl,line,timeout);    // en tΩte
  364.       _CHECK_HALT_FTP;
  365.       
  366.       if (line[0]=='2') {        // ok, connectΘ
  367.         strcpybuff(back->info,"login: user");
  368.         sprintf(line,"USER %s",user);
  369.         send_line(soc_ctl,line);
  370.         get_ftp_line(soc_ctl,line,timeout);
  371.         _CHECK_HALT_FTP;      
  372.         if ((line[0]=='3') || (line[0]=='2')) {
  373.           // --PASS--
  374.           strcpybuff(back->info,"login: pass");
  375.           sprintf(line,"PASS %s",pass);
  376.           send_line(soc_ctl,line);
  377.           get_ftp_line(soc_ctl,line,timeout);
  378.           _CHECK_HALT_FTP;      
  379.           if (line[0]=='2') {  // ok
  380.             send_line(soc_ctl,"TYPE I");
  381.             get_ftp_line(soc_ctl,line,timeout);
  382.             _CHECK_HALT_FTP;      
  383.             if (line[0]=='2') {
  384.               // ok
  385.             } else {
  386.               strcpybuff(back->r.msg,"TYPE I error");
  387.               // back->status=FTP_STATUS_READY;    // fini
  388.               back->r.statuscode=-1;
  389.             }
  390. #if 0
  391.             // --CWD--
  392.             char* a;
  393.             a=back->url_fil + strlen(back->url_fil)-1;
  394.             while( (a > back->url_fil) && (*a!='/')) a--;
  395.             if (*a == '/') {    // ok repΘrΘ
  396.               char BIGSTK target[1024];
  397.               target[0]='\0';
  398.               strncatbuff(target,back->url_fil,(int) (a - back->url_fil));
  399.               if (strnotempty(target)==0)
  400.                 strcatbuff(target,"/");
  401.               strcpybuff(back->info,"cwd");
  402.               sprintf(line,"CWD %s",target);
  403.               send_line(soc_ctl,line);
  404.               get_ftp_line(soc_ctl,line,timeout);
  405.               _CHECK_HALT_FTP;      
  406.               if (line[0]=='2') {
  407.                 send_line(soc_ctl,"TYPE I");
  408.                 get_ftp_line(soc_ctl,line,timeout);
  409.                 _CHECK_HALT_FTP;      
  410.                 if (line[0]=='2') {
  411.                   // ok..
  412.                 } else {
  413.                   strcpybuff(back->r.msg,"TYPE I error");
  414.                   // back->status=FTP_STATUS_READY;    // fini
  415.                   back->r.statuscode=-1;
  416.                 }
  417.               } else {
  418.                 sprintf(back->r.msg,"CWD error: %s",linejmp(line));
  419.                 // back->status=FTP_STATUS_READY;    // fini
  420.                 back->r.statuscode=-1;
  421.               }    // sinon on est prΩts
  422.             } else {
  423.               strcpybuff(back->r.msg,"Unexpected ftp error");
  424.               // back->status=FTP_STATUS_READY;    // fini
  425.               back->r.statuscode=-1;
  426.             }
  427. #endif
  428.             
  429.           } else {
  430.             sprintf(back->r.msg,"Bad password: %s",linejmp(line));
  431.             // back->status=FTP_STATUS_READY;    // fini
  432.             back->r.statuscode=-1;
  433.           }
  434.         } else {
  435.           sprintf(back->r.msg,"Bad user name: %s",linejmp(line));
  436.           // back->status=FTP_STATUS_READY;    // fini
  437.           back->r.statuscode=-1;
  438.         }
  439.       } else {
  440.         sprintf(back->r.msg,"Connection refused: %s",linejmp(line));
  441.         // back->status=FTP_STATUS_READY;    // fini
  442.         back->r.statuscode=-1;
  443.       }
  444.      
  445.       // ok, si on est prΩts on Θcoute sur un port et on demande la sauce
  446.       if (back->r.statuscode != -1) {
  447.  
  448.         
  449.         //
  450.         // PrΘ-REST
  451.         //
  452. #if FTP_PASV
  453.         if (SOCaddr_getproto(server, server_size) == '1') {
  454.           strcpybuff(back->info,"pasv");
  455.           sprintf(line,"PASV");
  456.           send_line(soc_ctl,line);
  457.           get_ftp_line(soc_ctl,line,timeout);
  458.         } else { /* ipv6 */
  459.           line[0]='\0';
  460.         }
  461.         _CHECK_HALT_FTP;      
  462.         if (line[0]=='2') {
  463.           char *a,*b,*c;
  464.           a=strchr(line,'(');       // exemple: 227 Entering Passive Mode (123,45,67,89,177,27)
  465.           if (a) {
  466.            
  467.             // -- analyse de l'adresse IP et du port --
  468.             a++;
  469.             b=strchr(a,',');
  470.             if (b) b=strchr(b+1,',');
  471.             if (b) b=strchr(b+1,',');
  472.             if (b) b=strchr(b+1,',');
  473.             c=a; while( (c=strchr(c,',')) ) *c='.';        // remplacer , par .
  474.             if (b) *b='\0';
  475.             //
  476.             strcpybuff(adr_ip,a);       // copier adresse ip
  477.             //
  478.             if (b) {
  479.               a=b+1;  // dΘbut du port
  480.               b=strchr(a,'.');
  481.               if (b) {
  482.                 int n1,n2;
  483.                 //
  484.                 *b='\0';
  485.                 b++;
  486.                 c=strchr(b,')');
  487.                 if (c) {
  488.                   *c='\0';
  489.                   if ( (sscanf(a,"%d",&n1)==1) && (sscanf(b,"%d",&n2)==1) && (strlen(adr_ip)<=16)) {
  490.                     port_pasv=n2+(n1<<8);
  491.                   }
  492.                 } else {
  493.                   deletesoc(soc_dat); soc_dat=INVALID_SOCKET;
  494.                 }    // sinon on est prΩts
  495.               }
  496.             }
  497.             // -- fin analyse de l'adresse IP et du port --
  498.           } else {
  499.             sprintf(back->r.msg,"PASV incorrect: %s",linejmp(line));
  500.             // back->status=FTP_STATUS_READY;    // fini
  501.             back->r.statuscode=-1;
  502.           }    // sinon on est prΩts
  503.         } else {
  504.           /*
  505.             * try epsv (ipv6) *
  506.           */
  507.           strcpybuff(back->info,"pasv");
  508.           sprintf(line,"EPSV");
  509.           send_line(soc_ctl,line);
  510.           get_ftp_line(soc_ctl,line,timeout);
  511.           _CHECK_HALT_FTP;      
  512.           if (line[0]=='2') { /* got it */
  513.             char *a;
  514.             a=strchr(line,'(');       // exemple: 229 Entering Extended Passive Mode (|||6446|)
  515.             if (
  516.               (a != NULL)
  517.               &&
  518.               (*a == '(') 
  519.               && (*(a+1))
  520.               && (*(a+1) == *(a+2)) && (*(a+1) == *(a+3))
  521.               && (isdigit(*(a+4)))
  522.               && (*(a+5))
  523.               ) {
  524.               unsigned int n1 = 0;
  525.               if (sscanf(a+4,"%d",&n1)==1) {
  526.                 if ((n1 < 65535) && (n1 > 0)) {
  527.                   port_pasv=n1;
  528.                 }
  529.               }
  530.             } else {
  531.               sprintf(back->r.msg,"EPSV incorrect: %s",linejmp(line));
  532.               // back->status=FTP_STATUS_READY;    // fini
  533.               back->r.statuscode=-1;
  534.             }
  535.           } else {
  536.             sprintf(back->r.msg,"PASV/EPSV error: %s",linejmp(line));
  537.             // back->status=FTP_STATUS_READY;    // fini
  538.             back->r.statuscode=-1;
  539.           }    // sinon on est prΩts
  540.         }
  541. #else
  542.         // rien α faire avant
  543. #endif
  544.           
  545. #if FTP_PASV
  546.         if (port_pasv) {
  547. #endif
  548.           // SIZE
  549.           if (back->r.statuscode != -1) {
  550.             if (!transfer_list) {
  551.               char* ua=unescape_http(ftp_filename);
  552.               if (
  553.                 (strchr(ua, ' '))
  554.                 ||
  555.                 (strchr(ua, '\"'))
  556.                 ||
  557.                 (strchr(ua, '\''))
  558.                 ) {
  559.                 sprintf(line,"SIZE \"%s\"", ua);
  560.               } else {
  561.                 sprintf(line,"SIZE %s", ua);
  562.               }
  563.               
  564.               // SIZE?
  565.               strcpybuff(back->info,"size");
  566.               send_line(soc_ctl,line);
  567.               get_ftp_line(soc_ctl,line,timeout);
  568.               _CHECK_HALT_FTP;      
  569.               if (line[0]=='2') {  // SIZE compris, ALORS tester REST (sinon pas tester: cf probleme des txt.gz decompresses a la volee)
  570.                 char* szstr = strchr(line, ' ');
  571.                 if (szstr) {
  572.                   LLint size = 0;
  573.                   szstr++;
  574.                   if (sscanf(szstr, LLintP, &size) == 1) {
  575.                     back->r.totalsize = size;
  576.                   }
  577.                 }
  578.  
  579.                 // REST?
  580.                 if (fexist(back->url_sav) && (transfer_list==0)) {
  581.                   strcpybuff(back->info,"rest");
  582.                   sprintf(line,"REST "LLintP,(LLint)fsize(back->url_sav));
  583.                   send_line(soc_ctl,line);
  584.                   get_ftp_line(soc_ctl,line,timeout);
  585.                   _CHECK_HALT_FTP;      
  586.                   if ((line[0]=='3') || (line[0]=='2')) {  // ok
  587.                     rest_understood=1;
  588.                   } // sinon tant pis 
  589.                 } 
  590.               }  // sinon tant pis 
  591.             }
  592.           }
  593. #if FTP_PASV
  594.         }
  595. #endif
  596.  
  597.         //
  598.         // Post-REST
  599.         //
  600. #if FTP_PASV
  601.         // Ok, se connecter
  602.         if (port_pasv) {
  603.           SOCaddr server;
  604.           int server_size=sizeof(server);
  605.           t_hostent* hp;    
  606.           // effacer structure
  607.           memset(&server, 0, sizeof(server));
  608.           
  609.           // infos
  610.           strcpybuff(back->info,"resolv");
  611.           
  612.           // rΘsoudre
  613.           if (adr_ip[0]) {
  614.             hp = hts_gethostbyname(adr_ip, &fullhostent_buffer);
  615.             if (hp) {
  616.               SOCaddr_copyaddr(server, server_size, hp->h_addr_list[0], hp->h_length);
  617.             } else {
  618.               server_size=0;
  619.             }
  620.           } else {
  621.             memcpy(&server, &server_data, sizeof(server_data));
  622.             server_size=server_data_size;
  623.           }
  624.           
  625.           // infos
  626.           strcpybuff(back->info,"cnxdata");
  627. #if FTP_DEBUG
  628.           printf("Data: Connecting to %s:%d...\n", adr_ip, port_pasv);
  629. #endif
  630.           if (server_size > 0) {
  631.             // socket
  632.             soc_dat=socket(SOCaddr_sinfamily(server), SOCK_STREAM, 0);
  633.             if (soc_dat != INVALID_SOCKET) {
  634.               // structure: connexion au domaine internet, port 80 (ou autre)
  635.               SOCaddr_initport(server, port_pasv);
  636.               // server.sin_port = htons((unsigned short int) port_pasv);
  637. #if HTS_WIN
  638.               if (connect(soc_dat, (const struct sockaddr FAR *)&server, server_size) == 0) {
  639. #else
  640.               if (connect(soc_dat, (struct sockaddr *)&server, server_size) != -1) {
  641. #endif
  642.                 strcpybuff(back->info,"retr");
  643.                 strcpybuff(line,line_retr);
  644.                 send_line(soc_ctl,line);
  645.                 get_ftp_line(soc_ctl,line,timeout);
  646.                 _CHECK_HALT_FTP;      
  647.                 if (line[0]=='1') {
  648.                   // OK
  649.                 } else {
  650.                   deletesoc(soc_dat); soc_dat=INVALID_SOCKET;
  651.                   //
  652.                   sprintf(back->r.msg,"RETR command errror: %s",linejmp(line));
  653.                   // back->status=FTP_STATUS_READY;    // fini
  654.                   back->r.statuscode=-1;
  655.                 }    // sinon on est prΩts
  656.               } else {
  657. #if FTP_DEBUG
  658.                 printf("Data: unable to connect\n");
  659. #endif
  660.                 deletesoc(soc_dat); soc_dat=INVALID_SOCKET;
  661.                 //
  662.                 strcpybuff(back->r.msg,"Unable to connect");
  663.                 // back->status=FTP_STATUS_READY;    // fini
  664.                 back->r.statuscode=-1;
  665.               }    // sinon on est prΩts
  666.             } else {
  667.               strcpybuff(back->r.msg,"Unable to create a socket");
  668.               // back->status=FTP_STATUS_READY;    // fini
  669.               back->r.statuscode=-1;
  670.             }    // sinon on est prΩts
  671.           } else {
  672.             sprintf(back->r.msg,"Unable to resolve IP %s",adr_ip);
  673.             // back->status=FTP_STATUS_READY;    // fini
  674.             back->r.statuscode=-1;
  675.           }    // sinon on est prΩts
  676.         } else {
  677.           sprintf(back->r.msg,"PASV incorrect: %s",linejmp(line));
  678.           // back->status=FTP_STATUS_READY;    // fini
  679.           back->r.statuscode=-1;
  680.         }    // sinon on est prΩts
  681. #else
  682.         //T_SOC soc_servdat;
  683.         strcpybuff(back->info,"listening");
  684.         if ( (soc_servdat = get_datasocket(line)) != INVALID_SOCKET) {
  685.           _CHECK_HALT_FTP;      
  686.           send_line(soc_ctl,line);          // envoi du RETR
  687.           get_ftp_line(soc_ctl,line,timeout);
  688.           _CHECK_HALT_FTP;      
  689.           if (line[0]=='2') {  // ok
  690.             strcpybuff(back->info,"retr");
  691.             strcpybuff(line,line_retr);
  692.             send_line(soc_ctl,line);
  693.             get_ftp_line(soc_ctl,line,timeout);
  694.             _CHECK_HALT_FTP;      
  695.             if (line[0]=='1') {
  696.               //T_SOC soc_dat;
  697.               struct sockaddr dummyaddr;
  698.               int dummylen = sizeof(struct sockaddr);
  699.               if ( (soc_dat=accept(soc_servdat,&dummyaddr,&dummylen)) == INVALID_SOCKET) {
  700.                 strcpybuff(back->r.msg,"Unable to accept connection");
  701.                 // back->status=FTP_STATUS_READY;    // fini
  702.                 back->r.statuscode=-1;
  703.               }
  704.             } else {
  705.               sprintf(back->r.msg,"RETR command errror: %s",linejmp(line));
  706.               // back->status=FTP_STATUS_READY;    // fini
  707.               back->r.statuscode=-1;
  708.             }
  709.           } else {
  710.             sprintf(back->r.msg,"PORT command error: %s",linejmp(line));
  711.             // back->status=FTP_STATUS_READY;    // fini
  712.             back->r.statuscode=-1;
  713.           }
  714. #if HTS_WIN
  715.           closesocket(soc_servdat);
  716. #else
  717.           close(soc_servdat);
  718. #endif
  719.         } else {
  720.           strcpybuff(back->r.msg,"Unable to listen to a port");
  721.           // back->status=FTP_STATUS_READY;    // fini
  722.           back->r.statuscode=-1;
  723.         }
  724. #endif
  725.         
  726.         //
  727.         // Ok, connexion initiΘe
  728.         //
  729.         if (soc_dat != INVALID_SOCKET) {
  730.           if (rest_understood) {         // REST envoyΘe et comprise
  731.             filenote(back->url_sav,NULL);
  732.             back->r.fp = fopen(fconv(back->url_sav),"ab");
  733.           } else
  734.             back->r.fp = filecreate(back->url_sav);
  735.           strcpybuff(back->info,"receiving");
  736.           if (back->r.fp != NULL) {
  737.             char BIGSTK buff[1024];
  738.             int len=1;
  739.             int read_len=1024;
  740.             //HTS_TOTAL_RECV_CHECK(read_len);         // Diminuer au besoin si trop de donnΘes reτues
  741.             
  742.             while( (len>0) && (!stop_ftp(back)) ) {
  743.               // attendre les donnΘes
  744.               len=1;    // pas d'erreur pour le moment
  745.               switch(wait_socket_receive(soc_dat,timeout)) {
  746.               case -1:
  747.                 strcpybuff(back->r.msg,"FTP read error");
  748.                 // back->status=FTP_STATUS_READY;    // fini
  749.                 back->r.statuscode=-1;
  750.                 len=0;    // fin
  751.                 break;
  752.               case 0:
  753.                 sprintf(back->r.msg,"Time out (%d)",timeout);
  754.                 // back->status=FTP_STATUS_READY;    // fini
  755.                 back->r.statuscode=-1;
  756.                 len=0;    // fin
  757.                 break;
  758.               }
  759.               
  760.               // rΘception
  761.               if (len) {
  762.                 len=recv(soc_dat,buff,read_len,0);
  763.                 if (len>0) {
  764.                   back->r.size+=len;
  765.                   HTS_STAT.HTS_TOTAL_RECV+=len; 
  766.                   if (back->r.fp) {
  767.                     if ((INTsys)fwrite(buff,1,(INTsys)len,back->r.fp) != len) {
  768.                       /*
  769.                       int fcheck;
  770.                       if ((fcheck=check_fatal_io_errno())) {
  771.                         opt->state.exit_xh=-1;
  772.                       }
  773.                       */
  774.                       strcpybuff(back->r.msg,"Write error");
  775.                       // back->status=FTP_STATUS_READY;    // fini
  776.                       back->r.statuscode=-1;
  777.                       len=0;  // error
  778.                     }
  779.                   } else {
  780.                     strcpybuff(back->r.msg,"Unexpected write error");
  781.                     // back->status=FTP_STATUS_READY;    // fini
  782.                     back->r.statuscode=-1;
  783.                   }
  784.                 } else {        // Erreur ou terminΘ
  785.                   // back->status=FTP_STATUS_READY;    // fini
  786.                   back->r.statuscode=0;
  787.                   if (back->r.totalsize > 0 && back->r.size != back->r.totalsize) {
  788.                     back->r.statuscode=-1;
  789.                     strcpybuff(back->r.msg,"FTP file incomplete");
  790.                   }
  791.                 }
  792.                 read_len=1024; 
  793.                 //HTS_TOTAL_RECV_CHECK(read_len);         // Diminuer au besoin si trop de donnΘes reτues
  794.               }
  795.             }
  796.             if (back->r.fp) { 
  797.               fclose(back->r.fp); 
  798.               back->r.fp=NULL;
  799.             }
  800.           } else {
  801.             strcpybuff(back->r.msg,"Unable to write file");
  802.             // back->status=FTP_STATUS_READY;    // fini
  803.             back->r.statuscode=-1;
  804.           }
  805. #if HTS_WIN
  806.           closesocket(soc_dat);
  807. #else
  808.           close(soc_dat);
  809. #endif
  810.           
  811.           // 226 Transfer complete?
  812.           if (back->r.statuscode != -1) {
  813.             if (wait_socket_receive(soc_ctl,timeout_onfly)>0) {
  814.               // rΘcupΘrer 226 transfer complete
  815.               get_ftp_line(soc_ctl,line,timeout);
  816.               if (line[0]=='2') {       // OK
  817.                 strcpybuff(back->r.msg,"OK");
  818.                 // back->status=FTP_STATUS_READY;    // fini
  819.                 back->r.statuscode=200;
  820.               } else {
  821.                 sprintf(back->r.msg,"RETR incorrect: %s",linejmp(line));
  822.                 // back->status=FTP_STATUS_READY;    // fini
  823.                 back->r.statuscode=-1;
  824.               }
  825.             } else {
  826.               strcpybuff(back->r.msg,"FTP read error");
  827.               // back->status=FTP_STATUS_READY;    // fini
  828.               back->r.statuscode=-1;
  829.             }
  830.           }
  831.           
  832.         }
  833.         
  834.         
  835.         
  836.       }
  837.       
  838.       
  839.     }
  840.     
  841.     _CHECK_HALT_FTP;
  842.     strcpybuff(back->info,"quit");
  843.     send_line(soc_ctl,"QUIT");    // bye bye
  844.     get_ftp_line(soc_ctl,NULL,timeout);
  845. #if HTS_WIN
  846.     closesocket(soc_ctl);
  847. #else
  848.     close(soc_ctl);
  849. #endif
  850.   }
  851.   
  852.   if (back->r.statuscode!=-1) {
  853.     back->r.statuscode=200;
  854.     strcpybuff(back->r.msg,"OK");
  855.   }
  856.   // back->status=FTP_STATUS_READY;    // fini
  857.   return 0;
  858. }
  859.  
  860.  
  861.  
  862. // ouverture d'un port
  863. T_SOC get_datasocket(char* to_send) {
  864.   T_SOC soc = INVALID_SOCKET;
  865.   char h_loc[256+2];
  866.   
  867.   to_send[0]='\0';
  868.   if (gethostname(h_loc,256)==0) {    // host name
  869.     SOCaddr server;
  870.     int server_size=sizeof(server);
  871.     t_hostent* hp_loc;
  872.     t_fullhostent buffer;
  873.  
  874.     // effacer structure
  875.     memset(&server, 0, sizeof(server));
  876.  
  877.     if ( (hp_loc=vxgethostbyname(h_loc, &buffer)) ) {  // notre host
  878.  
  879.       // copie adresse
  880.       SOCaddr_copyaddr(server, server_size, hp_loc->h_addr_list[0], hp_loc->h_length);
  881.  
  882.       if ( (soc=socket(SOCaddr_sinfamily(server), SOCK_STREAM, 0)) != INVALID_SOCKET) {
  883.  
  884.         if ( bind(soc,(struct sockaddr*) &server, server_size) == 0 ) {
  885.           SOCaddr server2;
  886.           int len;
  887.           len=sizeof(server2);
  888.           // effacer structure
  889.           memset(&server2, 0, sizeof(server2));
  890.           if (getsockname(soc,(struct sockaddr*) &server2, &len) == 0) {
  891.             // *port=ntohs(server.sin_port);  // rΘcupΘrer port
  892.             if (listen(soc,10)>=0) {    // au pif le 10
  893. #if HTS_INET6==0
  894.               unsigned short int a,n1,n2;
  895.               // calculer port
  896.               a  = SOCaddr_sinport(server2);
  897.               n1 = (a & 0xff);
  898.               n2 = ((a>>8) & 0xff);
  899.               {
  900.                 char dots[256+2];
  901.                 char dot[256+2];
  902.                 char* a;
  903.                 SOCaddr_inetntoa(dot, 256, server2, sizeof(server2));
  904.                 //
  905.                 dots[0]='\0';
  906.                 strncatbuff(dots, dot, 128);
  907.                 while( (a=strchr(dots,'.')) ) *a=',';    // virgules!
  908.                 while( (a=strchr(dots,':')) ) *a=',';    // virgules!
  909.                 sprintf(to_send,"PORT %s,%d,%d",dots,n1,n2);  
  910.               }
  911. #else
  912.               /*
  913.                 EPRT |1|132.235.1.2|6275|
  914.                 EPRT |2|1080::8:800:200C:417A|5282|
  915.               */
  916.               {
  917.                 char dot[256+2];
  918.                 SOCaddr_inetntoa(dot, 256, server2, len);
  919.                 sprintf(to_send,"EPRT |%c|%s|%d|", SOCaddr_getproto(server2, len), dot, SOCaddr_sinport(server2));  
  920.               }
  921. #endif
  922.               
  923.             } else {
  924. #if HTS_WIN
  925.               closesocket(soc);
  926. #else
  927.               close(soc);
  928. #endif
  929.               soc=INVALID_SOCKET;
  930.             }
  931.             
  932.             
  933.           } else {
  934. #if HTS_WIN
  935.             closesocket(soc);
  936. #else
  937.             close(soc);
  938. #endif
  939.             soc=INVALID_SOCKET;
  940.           }
  941.           
  942.           
  943.         } else {
  944. #if HTS_WIN
  945.           closesocket(soc);
  946. #else
  947.           close(soc);
  948. #endif
  949.           soc=INVALID_SOCKET;
  950.         }
  951.       }
  952.     }
  953.   }
  954.   
  955.   
  956.   return soc;
  957. }
  958.  
  959. #if FTP_DEBUG
  960. FILE* dd=NULL;
  961. #endif
  962.  
  963. // routines de rΘception/Θmission
  964. // 0 = ERROR
  965. int send_line(T_SOC soc,char* data) {
  966.   char BIGSTK line[1024];
  967.   if (_DEBUG_HEAD) {
  968.     if (ioinfo) {
  969.       fprintf(ioinfo,"---> %s\x0d\x0a",data);
  970.       fflush(ioinfo);
  971.     }
  972.   }
  973. #if FTP_DEBUG
  974.   if (dd == NULL) dd = fopen("toto.txt","w");
  975.   fprintf(dd,"---> %s\x0d\x0a",data); fflush(dd);
  976.   printf("---> %s",data); fflush(stdout);
  977. #endif
  978.   sprintf(line,"%s\x0d\x0a",data);
  979.   if (check_socket_connect(soc) != 1) {
  980. #if FTP_DEBUG
  981.     printf("!SOC WRITE ERROR\n");
  982. #endif
  983.     return 0;    // erreur, plus connectΘ!
  984.   }
  985. #if FTP_DEBUG
  986.   {
  987.     int r = (send(soc,line,strlen(line),0) == (int) strlen(line));
  988.     printf("%s\x0d\x0a",data); fflush(stdout);
  989.     return r;
  990.   }
  991. #else
  992.   return (send(soc,line,strlen(line),0) == (int) strlen(line));
  993. #endif
  994. }
  995.  
  996. int get_ftp_line(T_SOC soc,char* line,int timeout) {
  997.   char BIGSTK data[1024];
  998.   int i,ok,multiline;
  999. #if FTP_DEBUG
  1000.   if (dd == NULL) dd = fopen("toto.txt","w");
  1001. #endif
  1002.   
  1003.   data[0]='\0';
  1004.   i=ok=multiline=0; data[3]='\0';
  1005.   do {
  1006.     char b;                        
  1007.     
  1008.     // vΘrifier donnΘes
  1009.     switch(wait_socket_receive(soc,timeout)) {
  1010.     case -1:   // erreur de lecture
  1011.       if (line) strcpybuff(line,"500 *read error");
  1012.       return 0;
  1013.       break;
  1014.     case 0:
  1015.       if (line) sprintf(line,"500 *read timeout (%d)",timeout);
  1016.       return 0;
  1017.       break;
  1018.     }
  1019.     
  1020.     //HTS_TOTAL_RECV_CHECK(dummy);     // Diminuer au besoin si trop de donnΘes reτues
  1021.     switch(recv(soc,&b,1,0)) {
  1022.       //case 0: break;    // pas encore --> erreur (on attend)!
  1023.     case 1:
  1024.       HTS_STAT.HTS_TOTAL_RECV+=1; // compter flux entrant
  1025.       if ((b!=10) && (b!=13))
  1026.         data[i++]=b;
  1027.       break;
  1028.     default:
  1029.       if (line) strcpybuff(line,"500 *read error");
  1030.       return 0; // error
  1031.       break;
  1032.     }
  1033.     if ( ((b==13) || (b==10)) && (i>0) ){    // CR/LF
  1034.       if (
  1035.         (data[3] == '-')
  1036.         ||
  1037.         ((multiline) && (!isdigit((unsigned char)data[0]))) 
  1038.         )
  1039.       {
  1040.         data[3]='\0';
  1041.         i=0;
  1042.         multiline=1;
  1043.       }
  1044.       else
  1045.         ok=1;    // sortir
  1046.     }
  1047.   } while(!ok);
  1048.   data[i++]='\0';
  1049.   
  1050.   if (_DEBUG_HEAD) {
  1051.     if (ioinfo) {
  1052.       fprintf(ioinfo,"<--- %s\x0d\x0a",data);
  1053.       fflush(ioinfo);
  1054.     }
  1055.   }
  1056. #if FTP_DEBUG
  1057.   fprintf(dd,"<--- %s\n",data); fflush(dd);
  1058.   printf("<--- %s\n",data);
  1059. #endif
  1060.   if (line) strcpybuff(line,data);
  1061.   return (strnotempty(data));
  1062. }
  1063.  
  1064. // sauter NNN
  1065. char* linejmp(char* line) {
  1066.   if (strlen(line)>4)
  1067.     return line+4;
  1068.   else
  1069.     return line;
  1070. }
  1071.  
  1072. // test socket:
  1073. // 0 : no data
  1074. // 1 : data detected
  1075. // -1: error
  1076. int check_socket(T_SOC soc) {
  1077.   fd_set fds,fds_e;           // poll structures
  1078.   struct timeval tv;          // structure for select
  1079.   FD_ZERO(&fds);
  1080.   FD_ZERO(&fds_e); 
  1081.   // socket read 
  1082.   FD_SET(soc,&fds);           
  1083.   // socket error
  1084.   FD_SET(soc,&fds_e);
  1085.   tv.tv_sec=0;
  1086.   tv.tv_usec=0;
  1087.   // poll!     
  1088.   select(soc + 1,&fds,NULL,&fds_e,&tv);
  1089.   if (FD_ISSET(soc,&fds_e)) {  // error detected
  1090.     return -1;
  1091.   } else if (FD_ISSET(soc,&fds)) {
  1092.     return 1;
  1093.   }
  1094.   return 0;
  1095. }
  1096. // check if connected
  1097. int check_socket_connect(T_SOC soc) {
  1098.   fd_set fds,fds_e;           // poll structures
  1099.   struct timeval tv;          // structure for select
  1100.   FD_ZERO(&fds);
  1101.   FD_ZERO(&fds_e); 
  1102.   // socket write 
  1103.   FD_SET(soc,&fds);           
  1104.   // socket error
  1105.   FD_SET(soc,&fds_e);
  1106.   tv.tv_sec=0;
  1107.   tv.tv_usec=0;
  1108.   // poll!     
  1109.   select(soc + 1,NULL,&fds,&fds_e,&tv);
  1110.   if (FD_ISSET(soc,&fds_e)) {  // error detected
  1111.     return -1;
  1112.   } else if (FD_ISSET(soc,&fds)) {
  1113.     return 1;
  1114.   }
  1115.   return 0;
  1116. }
  1117. // attendre des donnΘes
  1118. int wait_socket_receive(T_SOC soc,int timeout) {
  1119.   // attendre les donnΘes
  1120.   TStamp ltime=time_local();
  1121.   int r;
  1122. #if FTP_DEBUG
  1123.   printf("\x0dWaiting for data "); fflush(stdout);
  1124. #endif
  1125.   while( (!(r = check_socket(soc))) && ( ((int) ((TStamp) (time_local()-ltime))) < timeout )) {
  1126.     Sleep(100);
  1127. #if FTP_DEBUG
  1128.     printf("."); fflush(stdout);
  1129. #endif
  1130.   }
  1131. #if FTP_DEBUG
  1132.   printf("\x0dreturn: %d\x0d",r); fflush(stdout);
  1133. #endif
  1134.   return r;
  1135. }
  1136.  
  1137.  
  1138. // cancel reτu?
  1139. int stop_ftp(lien_back* back) {
  1140.   if (back->stop_ftp) {
  1141.     strcpybuff(back->r.msg,"Cancelled by User");
  1142.     // back->status=FTP_STATUS_READY;    // fini
  1143.     back->r.statuscode=-1;
  1144.     return 1;
  1145.   }
  1146.   return 0;
  1147. }
  1148.  
  1149.  
  1150.  
  1151.  
  1152.